<?php
/**
 * Created by PhpStorm.
 * User: 姜伟
 * Date: 2018/5/10 0010
 * Time: 11:29
 */
namespace FPdf;

class SyPdf extends BasePdf
{
    /**
     * @var array
     */
    private $widthBig5 = [];
    /**
     * @var array
     */
    private $widthGB = [];

    public function __construct($orientation = 'P', $unit = 'mm', $size = 'A4')
    {
        parent::__construct($orientation, $unit, $size);
        $this->widthBig5 = [
            ' ' => 250,
            '!' => 250,
            '"' => 408,
            '#' => 668,
            '$' => 490,
            '%' => 875,
            '&' => 698,
            '\'' => 250,
            '(' => 240,
            ')' => 240,
            '*' => 417,
            '+' => 667,
            ',' => 250,
            '-' => 313,
            '.' => 250,
            '/' => 520,
            '0' => 500,
            '1' => 500,
            '2' => 500,
            '3' => 500,
            '4' => 500,
            '5' => 500,
            '6' => 500,
            '7' => 500,
            '8' => 500,
            '9' => 500,
            ':' => 250,
            ';' => 250,
            '<' => 667,
            '=' => 667,
            '>' => 667,
            '?' => 396,
            '@' => 921,
            'A' => 677,
            'B' => 615,
            'C' => 719,
            'D' => 760,
            'E' => 625,
            'F' => 552,
            'G' => 771,
            'H' => 802,
            'I' => 354,
            'J' => 354,
            'K' => 781,
            'L' => 604,
            'M' => 927,
            'N' => 750,
            'O' => 823,
            'P' => 563,
            'Q' => 823,
            'R' => 729,
            'S' => 542,
            'T' => 698,
            'U' => 771,
            'V' => 729,
            'W' => 948,
            'X' => 771,
            'Y' => 677,
            'Z' => 635,
            '[' => 344,
            '\\' => 520,
            ']' => 344,
            '^' => 469,
            '_' => 500,
            '`' => 250,
            'a' => 469,
            'b' => 521,
            'c' => 427,
            'd' => 521,
            'e' => 438,
            'f' => 271,
            'g' => 469,
            'h' => 531,
            'i' => 250,
            'j' => 250,
            'k' => 458,
            'l' => 240,
            'm' => 802,
            'n' => 531,
            'o' => 500,
            'p' => 521,
            'q' => 521,
            'r' => 365,
            's' => 333,
            't' => 292,
            'u' => 521,
            'v' => 458,
            'w' => 677,
            'x' => 479,
            'y' => 458,
            'z' => 427,
            '{' => 480,
            '|' => 496,
            '}' => 480,
            '~' => 667,
        ];

        $this->widthGB = [
            ' ' => 480,
            '!' => 480,
            '"' => 480,
            '#' => 480,
            '$' => 480,
            '%' => 480,
            '&' => 480,
            '\'' => 480,
            '(' => 480,
            ')' => 480,
            '*' => 480,
            '+' => 480,
            ',' => 480,
            '-' => 480,
            '.' => 480,
            '/' => 480,
            '0' => 462,
            '1' => 462,
            '2' => 462,
            '3' => 462,
            '4' => 462,
            '5' => 462,
            '6' => 462,
            '7' => 462,
            '8' => 462,
            '9' => 462,
            ':' => 480,
            ';' => 480,
            '<' => 480,
            '=' => 480,
            '>' => 480,
            '?' => 480,
            '@' => 480,
            'A' => 480,
            'B' => 480,
            'C' => 480,
            'D' => 480,
            'E' => 480,
            'F' => 480,
            'G' => 480,
            'H' => 480,
            'I' => 480,
            'J' => 480,
            'K' => 480,
            'L' => 480,
            'M' => 480,
            'N' => 480,
            'O' => 480,
            'P' => 480,
            'Q' => 480,
            'R' => 480,
            'S' => 480,
            'T' => 480,
            'U' => 480,
            'V' => 480,
            'W' => 480,
            'X' => 480,
            'Y' => 480,
            'Z' => 480,
            '[' => 480,
            '\\' => 480,
            ']' => 480,
            '^' => 480,
            '_' => 480,
            '`' => 480,
            'a' => 480,
            'b' => 480,
            'c' => 480,
            'd' => 480,
            'e' => 480,
            'f' => 480,
            'g' => 480,
            'h' => 480,
            'i' => 480,
            'j' => 480,
            'k' => 480,
            'l' => 480,
            'm' => 480,
            'n' => 480,
            'o' => 480,
            'p' => 480,
            'q' => 480,
            'r' => 480,
            's' => 480,
            't' => 480,
            'u' => 480,
            'v' => 480,
            'w' => 480,
            'x' => 480,
            'y' => 480,
            'z' => 480,
            '{' => 480,
            '|' => 480,
            '}' => 480,
            '~' => 480,
        ];
    }

    public function AddCIDFont($family, $style, $name, $cw, $CMap, $registry)
    {
        $fontkey = strtolower($family) . strtoupper($style);
        if (isset($this->fonts[$fontkey])) {
            $this->Error("Font already added: $family $style");
        }
        $i = count($this->fonts) + 1;
        $name = str_replace(' ', '', $name);
        $this->fonts[$fontkey] = [
            'i' => $i,
            'type' => 'Type0',
            'name' => $name,
            'up' => - 130,
            'ut' => 40,
            'cw' => $cw,
            'CMap' => $CMap,
            'registry' => $registry,
        ];
    }

    public function AddCIDFonts($family, $name, $cw, $CMap, $registry)
    {
        $this->AddCIDFont($family, '', $name, $cw, $CMap, $registry);
        $this->AddCIDFont($family, 'B', $name . ',Bold', $cw, $CMap, $registry);
        $this->AddCIDFont($family, 'I', $name . ',Italic', $cw, $CMap, $registry);
        $this->AddCIDFont($family, 'BI', $name . ',BoldItalic', $cw, $CMap, $registry);
    }

    public function AddBig5Font($family = 'PMingLiU', $name = 'MSungStd-Light-Acro')
    {
        //Add Big5 font with proportional Latin
        $CMap = 'ETenms-B5-H';
        $registry = ['ordering' => 'CNS1', 'supplement' => 0];
        $this->AddCIDFonts($family, $name, $this->widthBig5, $CMap, $registry);
    }

    public function AddBig5hwFont($family = 'PMingLiU', $name = 'MSungStd-Light-Acro')
    {
        //Add Big5 font with half-witdh Latin
        for ($i = 32; $i <= 126; $i ++) {
            $cw[chr($i)] = 500;
        }
        $CMap = 'ETen-B5-H';
        $registry = ['ordering' => 'CNS1', 'supplement' => 0];
        $this->AddCIDFonts($family, $name, $cw, $CMap, $registry);
    }

    public function AddGBFont($family = 'GB', $name = 'STSongStd-Light-Acro')
    {
        //Add GB font with proportional Latin
        $CMap = 'GBKp-EUC-H';
        $registry = ['ordering' => 'GB1', 'supplement' => 2];
        $this->AddCIDFonts($family, $name, $this->widthGB, $CMap, $registry);
    }

    public function AddGBhwFont($family = 'GB-hw', $name = 'STSongStd-Light-Acro')
    {
        //Add GB font with half-width Latin
        for ($i = 32; $i <= 126; $i ++) {
            $cw[chr($i)] = 500;
        }
        $CMap = 'GBK-EUC-H';
        $registry = ['ordering' => 'GB1', 'supplement' => 2];
        $this->AddCIDFonts($family, $name, $cw, $CMap, $registry);
    }

    public function GetStringWidth($s)
    {
        if ($this->CurrentFont['type'] == 'Type0') {
            return $this->GetMBStringWidth($s);
        } else {
            return parent::GetStringWidth($s);
        }
    }

    public function GetMBStringWidth($s)
    {
        //Multi-byte version of GetStringWidth()
        $l = 0;
        $cw = & $this->CurrentFont['cw'];
        $nb = strlen($s);
        $i = 0;
        while ($i < $nb) {
            $c = $s[$i];
            if (ord($c) < 128) {
                $l += $cw[$c];
                $i ++;
            } else {
                $l += 1000;
                $i += 2;
            }
        }

        return $l * $this->FontSize / 1000;
    }

    public function MultiCell($w, $h, $txt, $border = 0, $align = 'L', $fill = 0)
    {
        if ($this->CurrentFont['type'] == 'Type0') {
            $this->MBMultiCell($w, $h, $txt, $border, $align, $fill);
        } else {
            parent::MultiCell($w, $h, $txt, $border, $align, $fill);
        }
    }

    public function MBMultiCell($w, $h, $txt, $border = 0, $align = 'L', $fill = 0)
    {
        //Multi-byte version of MultiCell()
        $cw = & $this->CurrentFont['cw'];
        if ($w == 0) {
            $w = $this->w - $this->rMargin - $this->x;
        }
        $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
        $s = str_replace("\r", '', $txt);
        $nb = strlen($s);
        if ($nb > 0 and $s[$nb - 1] == "\n") {
            $nb --;
        }
        $b = 0;
        if ($border) {
            if ($border == 1) {
                $border = 'LTRB';
                $b = 'LRT';
                $b2 = 'LR';
            } else {
                $b2 = '';
                if (is_int(strpos($border, 'L'))) {
                    $b2 .= 'L';
                }
                if (is_int(strpos($border, 'R'))) {
                    $b2 .= 'R';
                }
                $b = is_int(strpos($border, 'T')) ? $b2 . 'T' : $b2;
            }
        }
        $sep = - 1;
        $i = 0;
        $j = 0;
        $l = 0;
        $nl = 1;
        while ($i < $nb) {
            //Get next character
            $c = $s[$i];
            //Check if ASCII or MB
            $ascii = (ord($c) < 128);
            if ($c == "\n") {
                //Explicit line break
                $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill);
                $i ++;
                $sep = - 1;
                $j = $i;
                $l = 0;
                $nl ++;
                if ($border and $nl == 2) {
                    $b = $b2;
                }
                continue;
            }
            if (!$ascii) {
                $sep = $i;
                $ls = $l;
            } elseif ($c == ' ') {
                $sep = $i;
                $ls = $l;
            }
            $l += $ascii ? $cw[$c] : 1000;
            if ($l > $wmax) {
                //Automatic line break
                if ($sep == - 1 or $i == $j) {
                    if ($i == $j) {
                        $i += $ascii ? 1 : 2;
                    }
                    $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill);
                } else {
                    $this->Cell($w, $h, substr($s, $j, $sep - $j), $b, 2, $align, $fill);
                    $i = ($s[$sep] == ' ') ? $sep + 1 : $sep;
                }
                $sep = - 1;
                $j = $i;
                $l = 0;
                $nl ++;
                if ($border and $nl == 2) {
                    $b = $b2;
                }
            } else {
                $i += $ascii ? 1 : 2;
            }
        }
        //Last chunk
        if ($border and is_int(strpos($border, 'B'))) {
            $b .= 'B';
        }
        $this->Cell($w, $h, substr($s, $j, $i - $j), $b, 2, $align, $fill);
        $this->x = $this->lMargin;
    }

    public function Write($h, $txt, $link = '')
    {
        if ($this->CurrentFont['type'] == 'Type0') {
            $this->MBWrite($h, $txt, $link);
        } else {
            parent::Write($h, $txt, $link);
        }
    }

    public function MBWrite($h, $txt, $link)
    {
        //Multi-byte version of Write()
        $cw = & $this->CurrentFont['cw'];
        $w = $this->w - $this->rMargin - $this->x;
        $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
        $s = str_replace("\r", '', $txt);
        $nb = strlen($s);
        $sep = - 1;
        $i = 0;
        $j = 0;
        $l = 0;
        $nl = 1;
        while ($i < $nb) {
            //Get next character
            $c = $s[$i];
            //Check if ASCII or MB
            $ascii = (ord($c) < 128);
            if ($c == "\n") {
                //Explicit line break
                $this->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, '', 0, $link);
                $i ++;
                $sep = - 1;
                $j = $i;
                $l = 0;
                if ($nl == 1) {
                    $this->x = $this->lMargin;
                    $w = $this->w - $this->rMargin - $this->x;
                    $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
                }
                $nl ++;
                continue;
            }
            if (!$ascii or $c == ' ') {
                $sep = $i;
            }
            $l += $ascii ? $cw[$c] : 1000;
            if ($l > $wmax) {
                //Automatic line break
                if ($sep == - 1 or $i == $j) {
                    if ($this->x > $this->lMargin) {
                        //Move to next line
                        $this->x = $this->lMargin;
                        $this->y += $h;
                        $w = $this->w - $this->rMargin - $this->x;
                        $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
                        $i ++;
                        $nl ++;
                        continue;
                    }
                    if ($i == $j) {
                        $i += $ascii ? 1 : 2;
                    }
                    $this->Cell($w, $h, substr($s, $j, $i - $j), 0, 2, '', 0, $link);
                } else {
                    $this->Cell($w, $h, substr($s, $j, $sep - $j), 0, 2, '', 0, $link);
                    $i = ($s[$sep] == ' ') ? $sep + 1 : $sep;
                }
                $sep = - 1;
                $j = $i;
                $l = 0;
                if ($nl == 1) {
                    $this->x = $this->lMargin;
                    $w = $this->w - $this->rMargin - $this->x;
                    $wmax = ($w - 2 * $this->cMargin) * 1000 / $this->FontSize;
                }
                $nl ++;
            } else {
                $i += $ascii ? 1 : 2;
            }
        }
        //Last chunk
        if ($i != $j) {
            $this->Cell($l / 1000 * $this->FontSize, $h, substr($s, $j, $i - $j), 0, 0, '', 0, $link);
        }
    }

    public function _putfonts()
    {
        $nf = $this->n;
        foreach ($this->diffs as $diff) {
            //Encodings
            $this->_newobj();
            $this->_out('<</Type /Encoding /BaseEncoding /WinAnsiEncoding /Differences [' . $diff . ']>>');
            $this->_out('endobj');
        }
        $mqr = get_magic_quotes_runtime();
        //set_magic_quotes_runtime(0);
        foreach ($this->FontFiles as $file => $info) {
            //Font file embedding
            $this->_newobj();
            $this->FontFiles[$file]['n'] = $this->n;
            if (defined('FPDF_FONTPATH')) {
                $file = FPDF_FONTPATH . $file;
            }
            $size = filesize($file);
            if (!$size) {
                $this->Error('Font file not found');
            }
            $this->_out('<</Length ' . $size);
            if (substr($file, - 2) == '.z') {
                $this->_out('/Filter /FlateDecode');
            }
            $this->_out('/Length1 ' . $info['length1']);
            if (isset($info['length2'])) {
                $this->_out('/Length2 ' . $info['length2'] . ' /Length3 0');
            }
            $this->_out('>>');
            $f = fopen($file, 'rb');
            $this->_putstream(fread($f, $size));
            fclose($f);
            $this->_out('endobj');
        }
        //set_magic_quotes_runtime($mqr);
        foreach ($this->fonts as $k => $font) {
            //Font objects
            $this->_newobj();
            $this->fonts[$k]['n'] = $this->n;
            $this->_out('<</Type /Font');
            if ($font['type'] == 'Type0') {
                $this->_putType0($font);
            } else {
                $name = $font['name'];
                $this->_out('/BaseFont /' . $name);
                if ($font['type'] == 'core') {
                    //Standard font
                    $this->_out('/Subtype /Type1');
                    if ($name != 'Symbol' and $name != 'ZapfDingbats') {
                        $this->_out('/Encoding /WinAnsiEncoding');
                    }
                } else {
                    //Additional font
                    $this->_out('/Subtype /' . $font['type']);
                    $this->_out('/FirstChar 32');
                    $this->_out('/LastChar 255');
                    $this->_out('/Widths ' . ($this->n + 1) . ' 0 R');
                    $this->_out('/FontDescriptor ' . ($this->n + 2) . ' 0 R');
                    if ($font['enc']) {
                        if (isset($font['diff'])) {
                            $this->_out('/Encoding ' . ($nf + $font['diff']) . ' 0 R');
                        } else {
                            $this->_out('/Encoding /WinAnsiEncoding');
                        }
                    }
                }
                $this->_out('>>');
                $this->_out('endobj');
                if ($font['type'] != 'core') {
                    //Widths
                    $this->_newobj();
                    $cw = & $font['cw'];
                    $s = '[';
                    for ($i = 32; $i <= 255; $i ++) {
                        $s .= $cw[chr($i)] . ' ';
                    }
                    $this->_out($s . ']');
                    $this->_out('endobj');
                    //Descriptor
                    $this->_newobj();
                    $s = '<</Type /FontDescriptor /FontName /' . $name;
                    foreach ($font['desc'] as $k => $v) {
                        $s .= ' /' . $k . ' ' . $v;
                    }
                    $file = $font['file'];
                    if ($file) {
                        $s .= ' /FontFile' . ($font['type'] == 'Type1' ? '' : '2') . ' ' . $this->FontFiles[$file]['n'] . ' 0 R';
                    }
                    $this->_out($s . '>>');
                    $this->_out('endobj');
                }
            }
        }
    }

    public function _putType0($font)
    {
        //Type0
        $this->_out('/Subtype /Type0');
        $this->_out('/BaseFont /' . $font['name'] . '-' . $font['CMap']);
        $this->_out('/Encoding /' . $font['CMap']);
        $this->_out('/DescendantFonts [' . ($this->n + 1) . ' 0 R]');
        $this->_out('>>');
        $this->_out('endobj');
        //CIDFont
        $this->_newobj();
        $this->_out('<</Type /Font');
        $this->_out('/Subtype /CIDFontType0');
        $this->_out('/BaseFont /' . $font['name']);
        $this->_out('/CIDSystemInfo <</Registry ' . $this->_textstring('Adobe') . ' /Ordering '
                    . $this->_textstring($font['registry']['ordering']) . ' /Supplement ' . $font['registry']['supplement'] . '>>');
        $this->_out('/FontDescriptor ' . ($this->n + 1) . ' 0 R');
        if ($font['CMap'] == 'ETen-B5-H') {
            $W = '13648 13742 500';
        } elseif ($font['CMap'] == 'GBK-EUC-H') {
            $W = '814 907 500 7716 [500]';
        } else {
            $W = '1 [' . implode(' ', $font['cw']) . ']';
        }
        $this->_out('/W [' . $W . ']>>');
        $this->_out('endobj');
        //Font descriptor
        $this->_newobj();
        $this->_out('<</Type /FontDescriptor');
        $this->_out('/FontName /' . $font['name']);
        $this->_out('/Flags 6');
        $this->_out('/FontBBox [0 -200 1000 900]');
        $this->_out('/ItalicAngle 0');
        $this->_out('/Ascent 800');
        $this->_out('/Descent -200');
        $this->_out('/CapHeight 800');
        $this->_out('/StemV 50');
        $this->_out('>>');
        $this->_out('endobj');
    }
}
